package sheep.utils.fileio;

import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Vertex;
import java.util.logging.Level;
import java.util.logging.Logger;
import sheep.controller.Workspace;
import java.io.*;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.Set;
import org.jdom.*;
import org.jdom.output.*;
import sheep.model.Calendrier;
import sheep.model.Note;
import sheep.model.Task;
import sheep.model.WorkGroup;
import sheep.model.Worker;
import sheep.model.graph.OurVertex;

public class WorkspaceSaver {
  private Workspace workSpace;
  private String fileName;
  private Document document;
  
  
  public WorkspaceSaver(Workspace w, String fileName) {
    this.workSpace = w;
    this.fileName = fileName;
  }
  
  // Permet de générer un élément Worker
  private Element generateWorker(Worker w) {
    Element worker = new Element("worker");

    Element id = new Element("id");
    id.addContent( Integer.toString(w.getId()) );
    worker.addContent(id);

    Element firstName = new Element("firstname");
    firstName.addContent( w.getFirstName() );
    worker.addContent(firstName);

    Element lastName = new Element("lastname");
    lastName.addContent(w.getLastName());
    worker.addContent(lastName);
    
    Element job = new Element("job");
    job.addContent(w.getJob());
    worker.addContent(job);
    
    Element picture = new Element("picture");
    picture.addContent(w.getPicturesURL());
    worker.addContent(picture);
    
    Element birthDate = new Element("birthdate");
    birthDate.addContent(Long.toString(w.getBirthDate().getTimeInMillis()));
    worker.addContent(birthDate);
    
    Element adress = new Element("address");
    adress.addContent(new Element("street").addContent(w.getAdresse()));
    adress.addContent(new Element("city").addContent(w.getTown()));
    adress.addContent(new Element("postalcode").addContent(w.getPostCode()));
    worker.addContent(adress);
    
    return worker;
  }
  
  // Permet de générer un élément workgroup
  public Element generateWorkGroup(WorkGroup w) {
    Element wg = new Element("workgroup");
      
    Element id = new Element("id");
    id.addContent(Integer.toString(w.getId()));
    wg.addContent(id);

    Element name = new Element("name");
    name.addContent(w.getName());
    wg.addContent(name);

    Element picture = new Element("picture");
    picture.addContent(w.getPictureURL());
    wg.addContent(picture);

    Element members = new Element("members");
    for(Worker w2 : w.getWorkersList()) {
      Element wk = new Element("member");
      wk.addContent(Integer.toString(w2.getId()));
      members.addContent(wk);
    }
    wg.addContent(members);
    
    return wg;
  }
  
  // Permet de générer le contenu XML d'une tâche
  public Element generateTask(Task t) {
    Element task = new Element("task");
    
    Element id = new Element("id").addContent(Integer.toString(t.getID()));
    task.addContent(id);
    
    Element name = new Element("name").addContent(t.getName());
    task.addContent(name);
    
    Element detailed = new Element("detailed").addContent(String.valueOf(t.isDetailled()));
    task.addContent(detailed);
    
    Element comment = new Element("comment").addContent(t.getComment());
    task.addContent(comment);
    
    Element location = new Element("location");
    location.addContent(new Element("xpos").addContent(Double.toString(t.getLocation().getX())));
    location.addContent(new Element("ypos").addContent(Double.toString(t.getLocation().getY())));
    task.addContent(location);
    
    Element duration = new Element("duration").addContent(Integer.toString(t.getDuration()));
    task.addContent(duration);
    
    Element actualBeginTime = new Element("actualbegintime").addContent(Long.toString(
            t.getActualBeginTime().getTimeInMillis()));
    task.addContent(actualBeginTime);
    
    Element actualEndTime = new Element("actualendtime").addContent(Long.toString(
            t.getActualEndTime().getTimeInMillis()));
    task.addContent(actualEndTime);
    
    Element earliestBeginTime = new Element("earliestbegintime").addContent(Long.toString(
            t.getEarliestBeginTime().getTimeInMillis()));
    task.addContent(earliestBeginTime);
    
    Element earliestEndTime = new Element("earliestendtime").addContent(Long.toString(
            t.getEarliestEndTime().getTimeInMillis()));
    task.addContent(earliestEndTime);
    
    Element latestBeginTime = new Element("latestbegintime").addContent(Long.toString(
            t.getLatestBeginTime().getTimeInMillis()));
    task.addContent(latestBeginTime);
    
    Element latestEndTime = new Element("latestendtime").addContent(Long.toString(
            t.getLatestEndTime().getTimeInMillis()));
    task.addContent(latestEndTime);
    
    Element state = new Element("state").addContent(t.getState().toString());
    task.addContent(state);
    
    Element mode = new Element("mode").addContent(t.getMode().toString());
    task.addContent(mode);
    
    Element managers = new Element("managers");
    for(Worker w : t.getManagers()) {
      Element manager = new Element("manager").addContent(Integer.toString(w.getId()));
      managers.addContent(manager);
    }
    task.addContent(managers);
    
    Element workers = new Element("workers");
    for(Worker w : t.getWorkersList()) {
      Element worker = new Element("worker").addContent(Integer.toString(w.getId()));
      workers.addContent(worker);
    }
    task.addContent(workers);
    
    Element predecessors = new Element("predecessors");
    if(t.getSuperTask() != null)
      for(Object o : t.getSuperTask().getGraph().getVertex(t).getPredecessors())
      {
        OurVertex p = (OurVertex)o;
        if(!p.getTask().getName().equals("start")){
          Element pred_id = new Element("id").addContent(Integer.toString(p.getTask().getID()));
          predecessors.addContent(pred_id);
        }
      }
    task.addContent(predecessors);
    
    Element children = new Element("children");
    if(t.isDetailled() && t.getGraph() != null)
    for(Object o : t.getGraph().getVertices())
    {
      Task child = ((OurVertex)o).getTask();
      if(!child.getName().equals("start") && !child.getName().equals("end"))
        children.addContent(generateTask(child));
    }
    task.addContent(children);
    
    return task;
  }
  
  public Element generateNote(Note n) {
    Element note = new Element("note");
      
    Element id = new Element("id").addContent(Integer.toString(n.getId()));
    note.addContent(id);
    
    Element startDate = new Element("startdate").addContent(Long.toString(n.getDate().getTimeInMillis()));
    note.addContent(startDate);
    
    Element endDate = new Element("enddate").addContent(Long.toString(n.getEndDate().getTimeInMillis()));
    note.addContent(endDate);
    
    Element title = new Element("title").addContent(n.getTitle());
    note.addContent(title);
    
    Element location = new Element("location").addContent(n.getLocation());
    note.addContent(location);
    
    Element comment = new Element("comment").addContent(n.getComment());
    note.addContent(comment);
    
//    Element calendar = new Element("calendar").addContent(Integer.toString(n.getCalendrier().getId()));
//    note.addContent(calendar);
    
    return note;
  }
  
  public Element generateCalendar(Calendrier c) {
    Element calendar = new Element("calendar");
    
    Element id = new Element("id").addContent(Integer.toString(c.getId()));
    calendar.addContent(id);
    
    Element name = new Element("name").addContent(c.getName());
    calendar.addContent(name);
    
    Element message = new Element("message").addContent(c.getMessage());
    calendar.addContent(message);
    
    Element color = new Element("color");
    color.addContent(new Element("red").addContent(Integer.toString(c.getColor().getRed())));
    color.addContent(new Element("green").addContent(Integer.toString(c.getColor().getGreen())));
    color.addContent(new Element("blue").addContent(Integer.toString(c.getColor().getBlue())));
    calendar.addContent(color);
    
    Element displayed = new Element("displayed").addContent(String.valueOf(c.isDisplay()));
    calendar.addContent(displayed);
    
    Element iconUrl = new Element("iconurl");
    if(c.getBuddyIconURL() != null)
      iconUrl.addContent(c.getBuddyIconURL().toString());
    calendar.addContent(iconUrl);
    
    Element notes = new Element("notes");
    for(Note n : c.getNoteList()){
      notes.addContent(generateNote(n));
    }
    
    calendar.addContent(notes);
    return calendar;
  }
  
  public Element generateWorkspace() {
    Element root = new Element("workspace");
    
    // On génère les participants
    Element rootWorkers = new Element("workers");
    for(Worker w : workSpace.getWorkersList()) {
      Element worker = generateWorker(w);
      rootWorkers.addContent(worker);
    }
    root.addContent(rootWorkers);
    
    // On génère les groupes
    Element rootWorkGroup = new Element("workgroups");
    for(WorkGroup w : workSpace.getWorkGroupsList()) {
      Element wg = generateWorkGroup(w);
      rootWorkGroup.addContent(wg);
    }
    root.addContent(rootWorkGroup);
    
    // On génère les tâches
    Element rootTask = new Element("projects");
    //Element rootEdge = new Element("edges");
    //LinkedList<Task> added = new LinkedList();
    for(Task t : workSpace.getProjectList()) {
      rootTask.addContent(this.generateTask(t));
      //added.add(t);
      //for(Task t2 : t.getTaskList(true, true)) {
        //if(!added.contains(t2))
          //added.add(t2);
    }
    
//    for(Task t : added)
//      rootTask.addContent(this.generateTask(t));
    root.addContent(rootTask);
    
//    for(Task t : workSpace.getProjectList()) {
//        generateSubGraph(t, null, rootEdge);
//    }
//    root.addContent(rootEdge);
    
    
    // On génère les calendriers
    Element rootCalendars = new Element("calendars");
    for(Calendrier c : workSpace.getCalendarList()) {
      Element calendar = generateCalendar(c);
      rootCalendars.addContent(calendar);
      
//      // On génère les notes
//      Element rootNotes = new Element("notes");
//      for(Note n : c.getNoteList()) {
//        Element note = generateNote(n);
//        rootNotes.addContent(note);
//      }
//      calendar.addContent(rootNotes);
      
    }
    root.addContent(rootCalendars);
    
    
    // On sauve le chemin du fichier de maniere a ouvrir le workspace lors
    // du prochain lancement de l'application
    WorkspaceAutoLoader wl = new WorkspaceAutoLoader(workSpace);
    wl.saveWorkspace();
    
    return root;
  }
  
  private void generateSubGraph(Task t, LinkedList<Task> done, Element root) {
    
    if(done==null) done = new LinkedList<Task>();
    
    if(t.isDetailled() && t.getGraph() != null) {
      for(Object o : t.getGraph().getVertices()) {
        generateSubGraph(((OurVertex)o).getTask(), done, root);
      }
    }
    else {
      
      if(!done.contains(t.getSuperTask()) && t.getSuperTask() != null && t.getSuperTask().getGraph()!=null) {
        for(Object o : t.getSuperTask().getGraph().getEdges()) {
          Edge e = (Edge)o;
          if(!((OurVertex)e.getEndpoints().getFirst()).getTask().getName().equals("start") && 
             !((OurVertex)e.getEndpoints().getSecond()).getTask().getName().equals("end")) {
            Element ed = new Element("edge");
            ed.addContent(new Element("start").addContent(String.valueOf(((OurVertex)e.getEndpoints().getFirst()).getTask().getID())));
            ed.addContent(new Element("end").addContent(String.valueOf(((OurVertex)e.getEndpoints().getSecond()).getTask().getID())));
            root.addContent(ed);
          }
        }
        done.add(t.getSuperTask());
      }
      
    }
    
    
  }
  
  public void save(Element root) {
    document = new Document(root);
    
    XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
    try {
      out.output(document, new FileOutputStream(fileName));
    } catch (IOException ex) {
      Logger.getLogger(WorkspaceSaver.class.getName()).log(Level.SEVERE, null, ex);
    }
  }
  
}